package controllers.customer;

import java.util.Collection;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import services.AvailableItemService;
import services.CommentService;
import services.CustomerService;
import services.PurchasedItemService;
import services.ShoppingCartItemUnitService;
import controllers.AbstractController;
import domain.AvailableItem;
import domain.Comment;
import domain.Customer;
import domain.PurchasedItem;
import domain.ShoppingCartItemUnit;
import forms.ItemForm;

@Controller
@RequestMapping("/availableItem/customer")
public class AvailableItemCustomerController extends AbstractController {

	// Services
	@Autowired
	private AvailableItemService availableItemService;
	@Autowired
	private PurchasedItemService purchasedItemService;
	@Autowired
	private CustomerService customerService;
	@Autowired
	private CommentService commentService;
	@Autowired
	private ShoppingCartItemUnitService shoppingCartItemUnitService;

	// Constructors

	public AvailableItemCustomerController() {
		super();
	}

	// Listing methods
	@RequestMapping(value = "/list", method = RequestMethod.GET)
	public ModelAndView list() {
		ModelAndView result;
		Collection<AvailableItem> availableItems;
		int customerId;

		customerId = customerService.findByPrincipal().getId();
		availableItems = availableItemService.findAvailableItems();

		result = new ModelAndView("availableItem/list");
		result.addObject("requestURI", "availableItem/customer/list.do");
		result.addObject("availableItems", availableItems);
		result.addObject("customerId", customerId);
		result.addObject("backURI", "/welcome/index.do");
		return result;
	}

	@RequestMapping(value = "/itemsToAddCart", method = RequestMethod.GET)
	public ModelAndView itemsToAddCart() {
		ModelAndView result;
		Collection<AvailableItem> availableItems;
		int customerId;

		customerId = customerService.findByPrincipal().getId();
		availableItems = availableItemService
				.findAvailableItemsByOthersCustomer();

		result = new ModelAndView("availableItem/list");
		result.addObject("requestURI", "availableItem/customer/list.do");
		result.addObject("availableItems", availableItems);
		result.addObject("customerId", customerId);
		result.addObject("backURI", "/welcome/index.do");
		return result;
	}

	@RequestMapping(value = "/listOnSale", method = RequestMethod.GET)
	public ModelAndView listOnSale() {
		ModelAndView result;
		Collection<AvailableItem> availableItems;
		Boolean isSeller;
		int customerId;

		customerId = customerService.findByPrincipal().getId();
		isSeller = true;
		availableItems = availableItemService.findAvailableItemsBySellerId();

		result = new ModelAndView("availableItem/customer/listOnSale");
		result.addObject("requestURI", "availableItem/customer/listOnSale.do");
		result.addObject("availableItems", availableItems);
		result.addObject("customerId", customerId);
		result.addObject("isSeller", isSeller);

		result.addObject("backURI", "/welcome/index.do");
		return result;
	}

	@RequestMapping(value = "/listBestRating", method = RequestMethod.GET)
	public ModelAndView listBestRating() {
		ModelAndView result;
		Collection<AvailableItem> availableItems;
		int customerId;

		customerId = customerService.findByPrincipal().getId();
		availableItems = availableItemService.findBestRatedBySeller();

		result = new ModelAndView("bestRatedItem/list");
		result.addObject("requestURI",
				"availableItem/customer/listBestRating.do");
		result.addObject("availableItems", availableItems);
		result.addObject("customerId", customerId);

		result.addObject("backURI", "/welcome/index.do");
		return result;
	}

	// Creation
	@RequestMapping(value = "/create", method = RequestMethod.GET)
	public ModelAndView create() {
		ModelAndView result;
		ItemForm itemForm;
		AvailableItem ai;
		Boolean isNew;
		ai = availableItemService.create();
		itemForm = availableItemService.availableItemToForm(ai);
		isNew = true;

		result = new ModelAndView("availableItem/create");
		result.addObject("itemForm", itemForm);
		result.addObject("requestURI", "availableItem/customer/edit.do");
		result.addObject("isNew", isNew);
		result.addObject("backURI", "/welcome/index.do");

		return result;

	}

	// Edition

	@RequestMapping(value = "/edit", method = RequestMethod.GET)
	public ModelAndView edit(@RequestParam int availableItemId) {
		ModelAndView result;
		Boolean isNew;
		Boolean isSeller;
		Boolean hasOrder;
		Boolean isBuyer;
		Boolean wished;
		Boolean available;
		Boolean inCart;
		Boolean max;
		AvailableItem availableItem;
		ItemForm itemForm;
		Customer principal;
		Collection<Comment> comments;
		Collection<PurchasedItem> purchasedItems;
		ShoppingCartItemUnit sciu;

		comments = commentService.findCommentsByItemId(availableItemId);
		availableItem = availableItemService.findOne(availableItemId);
		itemForm = availableItemService.availableItemToForm(availableItem);
		principal = customerService.findByPrincipal();

		isNew = false;
		isSeller = !isNew && availableItem.getSeller().equals(principal);
		isBuyer = purchasedItemService.isBuyer(availableItem);
		purchasedItems = purchasedItemService
				.findPurchasedItemIdByAvailableItemRefNumber(availableItem
						.getReferenceNumber());
		sciu = shoppingCartItemUnitService.findByCustomerAndItem(availableItem);

		hasOrder = !purchasedItems.isEmpty();

		wished = principal.getWishList().contains(availableItem);
		inCart = availableItemService.findCartItems().contains(availableItem);
		available = availableItem.getAvailableUnits() > 0;

		if (sciu == null) {
			max = false;
		} else {
			max = availableItem.getAvailableUnits() == sciu.getNumberOfItems();
		}

		result = new ModelAndView("availableItem/edit");

		result.addObject("requestURI", "availableItem/customer/edit.do");
		result.addObject("isNew", isNew);
		result.addObject("itemForm", itemForm);
		result.addObject("comments", comments);
		result.addObject("availableItemId", availableItemId);
		result.addObject("isSeller", isSeller);
		result.addObject("isBuyer", isBuyer);
		result.addObject("itemId", itemForm.getItemId());
		result.addObject("hasOrder", hasOrder);
		result.addObject("wished", wished);
		result.addObject("available", available);
		result.addObject("max", max);
		result.addObject("inCart", inCart);
		result.addObject("backURI", "/welcome/index.do");

		return result;

	}

	@RequestMapping(value = "/edit", method = RequestMethod.POST, params = "save")
	public ModelAndView save(@Valid ItemForm itemForm, BindingResult binding) {
		ModelAndView result;
		AvailableItem ai;
		Boolean isNew;
		Boolean isSeller;
		Boolean hasOrder;
		Customer principal;
		Collection<PurchasedItem> purchasedItems;

		int aiId;
		aiId = itemForm.getItemId();
		purchasedItems = purchasedItemService
				.findPurchasedItemIdByAvailableItemRefNumber(itemForm
						.getReferenceNumber());

		if (binding.hasErrors()) {
			result = createEditModelAndView(itemForm);
		} else {
			try {
				ai = availableItemService.reconstruct(itemForm);

				availableItemService.save(ai);
				result = new ModelAndView("redirect:../../");

			} catch (Throwable oops) {

				result = createEditModelAndView(itemForm,
						"availableItem.commit.error");
			}
		}

		principal = customerService.findByPrincipal();
		isNew = aiId == 0;
		isSeller = !isNew && itemForm.getSeller().equals(principal);

		hasOrder = !purchasedItems.isEmpty();

		result.addObject("requestURI", "availableItem/customer/edit.do");
		result.addObject("aiId", aiId);
		result.addObject("isNew", isNew);
		result.addObject("isSeller", isSeller);
		result.addObject("hasOrder", hasOrder);

		return result;
	}

	@RequestMapping(value = "/edit", method = RequestMethod.POST, params = "delete")
	public ModelAndView delete(ItemForm itemForm, BindingResult binding) {
		ModelAndView result;
		AvailableItem ai;
		int aiId;
		Boolean isNew;
		Boolean isSeller;
		Boolean hasOrder;
		Collection<PurchasedItem> purchasedItems;

		purchasedItems = purchasedItemService
				.findPurchasedItemIdByAvailableItemRefNumber(itemForm
						.getReferenceNumber());

		aiId = itemForm.getItemId();
		ai = availableItemService.findOne(aiId);
		isNew = false;
		isSeller = true;
		hasOrder = !purchasedItems.isEmpty();
		try {
			availableItemService.delete(ai);
			result = new ModelAndView("redirect:../../");

		} catch (Throwable oops) {
			result = createEditModelAndView(itemForm,
					"availableItem.commit.error");
		}
		result.addObject("requestURI", "availableItem/customer/edit.do");
		result.addObject("isNew", isNew);
		result.addObject("isSeller", isSeller);
		result.addObject("hasOrder", hasOrder);

		return result;

	}

	// WishList

	@RequestMapping(value = "/addToWishlist", method = RequestMethod.GET)
	public ModelAndView addWish(@RequestParam int availableItemId) {
		ModelAndView result;
		AvailableItem availableItem;
		Collection<AvailableItem> availableItems;
		Boolean wishedItems;

		availableItem = availableItemService.findOne(availableItemId);
		availableItemService.addToWishlist(availableItem);

		availableItems = availableItemService.findWishedItems();
		wishedItems = !availableItems.isEmpty();

		result = new ModelAndView("wish/list");
		result.addObject("requestURI", "availableItem/customer/listWish.do");
		result.addObject("wishedItems", wishedItems);
		result.addObject("availableItems", availableItems);
		result.addObject("backURI", "/welcome/index.do");
		return result;
	}

	@RequestMapping(value = "/removeFromWishlist", method = RequestMethod.GET)
	public ModelAndView removeWish(@RequestParam int availableItemId) {
		ModelAndView result;
		AvailableItem availableItem;
		Collection<AvailableItem> availableItems;
		Boolean wishedItems;

		availableItem = availableItemService.findOne(availableItemId);
		availableItemService.removeFromWishlist(availableItem);

		availableItems = availableItemService.findWishedItems();
		wishedItems = !availableItems.isEmpty();

		result = new ModelAndView("wish/list");
		result.addObject("requestURI", "availableItem/customer/listWish.do");
		result.addObject("availableItems", availableItems);
		result.addObject("wishedItems", wishedItems);
		result.addObject("backURI", "/welcome/index.do");
		return result;
	}

	@RequestMapping(value = "/emptyWishList", method = RequestMethod.POST)
	public ModelAndView emptyWish() {
		ModelAndView result;
		Collection<AvailableItem> availableItems;
		Boolean wishedItems;

		availableItemService.emptyWishList();

		availableItems = availableItemService.findWishedItems();
		wishedItems = !availableItems.isEmpty();

		result = new ModelAndView("wish/list");
		result.addObject("requestURI", "availableItem/customer/listWish.do");
		result.addObject("availableItems", availableItems);
		result.addObject("wishedItems", wishedItems);
		result.addObject("backURI", "/welcome/index.do");
		return result;
	}

	@RequestMapping(value = "/listWish", method = RequestMethod.GET)
	public ModelAndView listWish() {
		ModelAndView result;
		Collection<AvailableItem> availableItems;
		Boolean wishedItems;

		availableItems = availableItemService.findWishedItems();
		wishedItems = !availableItems.isEmpty();

		result = new ModelAndView("wish/list");
		result.addObject("requestURI", "availableItem/customer/listWish.do");
		result.addObject("availableItems", availableItems);
		result.addObject("wishedItems", wishedItems);
		result.addObject("backURI", "/welcome/index.do");
		return result;
	}

	// Shopping Cart

	@RequestMapping(value = "/listCart", method = RequestMethod.GET)
	public ModelAndView listCart() {
		ModelAndView result;
		Collection<ShoppingCartItemUnit> scius;
		Boolean itemsInCart;

		scius = shoppingCartItemUnitService.findByCustomer();
		itemsInCart = !scius.isEmpty();

		result = new ModelAndView("cart/list");
		result.addObject("requestURI", "availableItem/customer/listCart.do");
		result.addObject("scius", scius);
		result.addObject("itemsInCart", itemsInCart);
		result.addObject("backURI", "/welcome/index.do");
		return result;
	}

	@RequestMapping(value = "/addToCart", method = RequestMethod.GET)
	public ModelAndView addCart(@RequestParam int availableItemId) {
		ModelAndView result;
		AvailableItem availableItem;
		Collection<ShoppingCartItemUnit> scius;
		Boolean itemsInCart;

		availableItem = availableItemService.findOne(availableItemId);
		availableItemService.addToCart(availableItem);

		scius = shoppingCartItemUnitService.findByCustomer();
		itemsInCart = !scius.isEmpty();

		result = new ModelAndView("cart/list");
		result.addObject("requestURI", "availableItem/customer/listCart.do");
		result.addObject("itemsInCart", itemsInCart);
		result.addObject("scius", scius);
		result.addObject("backURI", "/welcome/index.do");
		return result;
	}

	@RequestMapping(value = "/addAnotherToCart", method = RequestMethod.GET)
	public ModelAndView addAnotherCart(@RequestParam int availableItemId) {
		ModelAndView result;
		AvailableItem availableItem;
		Collection<ShoppingCartItemUnit> scius;
		Boolean itemsInCart;

		availableItem = availableItemService.findOne(availableItemId);
		availableItemService.addAnotherUnit(availableItem);

		scius = shoppingCartItemUnitService.findByCustomer();
		itemsInCart = !scius.isEmpty();

		result = new ModelAndView("cart/list");
		result.addObject("requestURI", "availableItem/customer/listCart.do");
		result.addObject("itemsInCart", itemsInCart);
		result.addObject("scius", scius);
		result.addObject("backURI", "/welcome/index.do");
		return result;
	}

	@RequestMapping(value = "/changeUnitsCart", method = RequestMethod.GET)
	public ModelAndView addAnotherCartGet(@RequestParam int shoppingCartId) {
		ModelAndView result;
		ShoppingCartItemUnit shoppingCart;

		shoppingCart = shoppingCartItemUnitService.findOne(shoppingCartId);

		result = new ModelAndView("cart/changeUnit");
		result.addObject("requestURI",
				"availableItem/customer/changeUnitsCart.do");
		result.addObject("shoppingCart", shoppingCart);

		result.addObject("backURI", "/availableItem/customer/listCart.do");
		return result;
	}

	@RequestMapping(value = "/changeUnitsCart", method = RequestMethod.POST)
	public ModelAndView changeUnitsCart(
			@Valid ShoppingCartItemUnit shoppingCartItemUnit,
			BindingResult binding) {
		ModelAndView result;
		Collection<ShoppingCartItemUnit> scius;
		Boolean itemsInCart;
		if (binding.hasErrors()) {
			result = new ModelAndView("cart/changeUnit");
			result.addObject("message", "error.units.write");
			result.addObject("requestURI",
					"availableItem/customer/changeUnitsCart.do");
			result.addObject("shoppingCart", shoppingCartItemUnit);
			result.addObject("backURI", "/availableItem/customer/listCart.do");
			return result;
		} else {
			try {
				result = new ModelAndView("cart/list");

				shoppingCartItemUnitService
						.changeUntisAndSave(shoppingCartItemUnit);
			} catch (Throwable oops) {
				result = new ModelAndView("cart/changeUnit");
				result.addObject("requestURI",
						"availableItem/customer/changeUnitsCart.do");
				result.addObject("shoppingCart", shoppingCartItemUnit);

				result.addObject("backURI",
						"/availableItem/customer/listCart.do");

				result.addObject("message", "error.change.Units");

				return result;
			}
			scius = shoppingCartItemUnitService.findByCustomer();
			itemsInCart = !scius.isEmpty();
			result.addObject("requestURI", "availableItem/customer/listCart.do");
			result.addObject("scius", scius);
			result.addObject("itemsInCart", itemsInCart);
			result.addObject("backURI", "/welcome/index.do");

			return result;

		}
	}

	@RequestMapping(value = "/removeFromCart", method = RequestMethod.GET)
	public ModelAndView removeCart(@RequestParam int availableItemId) {
		ModelAndView result;
		AvailableItem availableItem;
		Collection<ShoppingCartItemUnit> scius;
		Boolean itemsInCart;

		availableItem = availableItemService.findOne(availableItemId);
		availableItemService.removeFromCart(availableItem);

		scius = shoppingCartItemUnitService.findByCustomer();
		itemsInCart = !scius.isEmpty();

		result = new ModelAndView("cart/list");
		result.addObject("requestURI", "availableItem/customer/listCart.do");
		result.addObject("scius", scius);
		result.addObject("itemsInCart", itemsInCart);
		result.addObject("backURI", "/welcome/index.do");
		return result;
	}

	@RequestMapping(value = "/emptyCart", method = RequestMethod.POST)
	public ModelAndView emptyCart() {
		ModelAndView result;
		Collection<ShoppingCartItemUnit> scius;
		Boolean itemsInCart;

		availableItemService.emptyCart();

		scius = shoppingCartItemUnitService.findByCustomer();
		itemsInCart = !scius.isEmpty();

		result = new ModelAndView("cart/list");
		result.addObject("requestURI", "availableItem/customer/listCart.do");
		result.addObject("scius", scius);
		result.addObject("itemsInCart", itemsInCart);
		result.addObject("backURI", "/welcome/index.do");
		return result;
	}

	// Ancillary methods
	protected ModelAndView createEditModelAndView(ItemForm itemForm) {
		ModelAndView result;

		result = createEditModelAndView(itemForm, null);

		return result;
	}

	protected ModelAndView createEditModelAndView(ItemForm itemForm,
			String message) {
		ModelAndView result;

		result = new ModelAndView("availableItem/edit");

		result.addObject("itemForm", itemForm);
		result.addObject("message", message);

		return result;
	}

}
